﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using Microsoft.VisualStudio.TextTemplating;

namespace Flywheel.T4Host
{
	[Serializable]
	public class TextTemplateHost : MarshalByRefObject, ITextTemplatingEngineHost, ITemplateContext
	{
		private string _outputPath;
		private AppDomain domain;
		private CompilerErrorCollection errorsValue;
		private Encoding fileEncodingValue = Encoding.UTF8;
		private string fileExtensionValue = ".txt";

		private string TemplateFileValue;
	    public int BuildAction
	    {
            get
            {
                object buildaction = domain.GetData("buildaction");
                if(buildaction!=null)
                {
                    return (int)buildaction ;
                }
                else
                {
                    return 1;
                }
                
            }
	    }
		public string OutputPath
		{
			get { return (string) domain.GetData("outputpath"); }
			set { _outputPath = value; }
		}

		public string AssemblyPath { get; set; }


		public CompilerErrorCollection Errors
		{
			get { return errorsValue; }
		}

		public Encoding FileEncoding
		{
			get { return fileEncodingValue; }
		}

		public string FileExtension
		{
			get { return fileExtensionValue; }
		}

		public string TemplateFile
		{
			set { TemplateFileValue = value; }
		}

		#region ITemplateContext Members

		public ModelType Model { get; set; }
		public string ProjectDefaultNamespace { get; set; }
		public string ProjectDirectory { get; set; }

		#endregion

		#region ITextTemplatingEngineHost Members

		object ITextTemplatingEngineHost.GetHostOption(string optionName)
		{
			string str;
			return (((str = optionName) != null) && (str == "CacheAssemblies"));
		}

		bool ITextTemplatingEngineHost.LoadIncludeText(string requestFileName, out string content, out string location)
		{
			content = String.Empty;
			location = String.Empty;

			//If the argument is the fully qualified path of an existing file,
			//then we are done.
			//----------------------------------------------------------------
			if (File.Exists(requestFileName))
			{
				content = File.ReadAllText(requestFileName);
				return true;
			}

				//This can be customized to search specific paths for the file.
				//This can be customized to accept paths to search as command line
				//arguments.
				//----------------------------------------------------------------
			else
			{
				return false;
			}
		}

		void ITextTemplatingEngineHost.LogErrors(CompilerErrorCollection errors)
		{
			errorsValue = errors;
		}

		AppDomain ITextTemplatingEngineHost.ProvideTemplatingAppDomain(string content)
		{
			// Set up the AppDomainSetup
			var setup = new AppDomainSetup();
			setup.ApplicationBase = AssemblyPath;


			// Create the AppDomain      
			domain = AppDomain.CreateDomain("Generation App Domain", null, setup);
			domain.SetData("host", this);
			return domain;
		}

		string ITextTemplatingEngineHost.ResolveAssemblyReference(string assemblyReference)
		{
			if (File.Exists(assemblyReference))
			{
				return assemblyReference;
			}
			string path = Path.Combine(Path.GetDirectoryName(((ITextTemplatingEngineHost) this).TemplateFile), assemblyReference);
			if (File.Exists(path))
			{
				return path;
			}
			return "";
		}

		Type ITextTemplatingEngineHost.ResolveDirectiveProcessor(string processorName)
		{
			throw new Exception("Directive Processor " + processorName + " not found");
		}

		string ITextTemplatingEngineHost.ResolveParameterValue(string directiveId, string processorName, string parameterName)
		{
			if (directiveId == null)
			{
				throw new ArgumentNullException("the directiveId cannot be null");
			}
			if (processorName == null)
			{
				throw new ArgumentNullException("the processorName cannot be null");
			}
			if (parameterName == null)
			{
				throw new ArgumentNullException("the parameterName cannot be null");
			}
			return string.Empty;
		}

		string ITextTemplatingEngineHost.ResolvePath(string path)
		{
			if (path == null)
			{
				throw new ArgumentNullException("the file name cannot be null");
			}
			if (!File.Exists(path))
			{
				string str = Path.Combine(Path.GetDirectoryName(((ITextTemplatingEngineHost) this).TemplateFile), path);
				if (File.Exists(str))
				{
					return str;
				}
			}
			return path;
		}

		void ITextTemplatingEngineHost.SetFileExtension(string extension)
		{
			fileExtensionValue = extension;
		}

		void ITextTemplatingEngineHost.SetOutputEncoding(Encoding encoding, bool fromOutputDirective)
		{
			fileEncodingValue = encoding;
		}

		IList<string> ITextTemplatingEngineHost.StandardAssemblyReferences
		{
			get
			{
				return new[]
				       	{
				       		typeof (Uri).Assembly.Location, Assembly.GetExecutingAssembly().Location,
				       		typeof (ModelType).Assembly.Location
				       	};
			}
		}

		IList<string> ITextTemplatingEngineHost.StandardImports
		{
			get { return new[] {"System", typeof (TextTemplateHost).Namespace, typeof (ModelType).Namespace}; }
		}

		string ITextTemplatingEngineHost.TemplateFile
		{
			get { return TemplateFileValue; }
		}

		#endregion
	}
}